"""
 * @file main.py
 * @author SDK_TEAM
 * @brief
 * @version 0.1
 * @date 2024-05-09
 * Copyright:
 * © 2018 北京灵汐科技有限公司 版权所有。
 * 注意：以下内容均为北京灵汐科技有限公司原创，未经本公司允许，不得转载，否则将视为侵权；对于不遵守此声明或者其他违法使用以下内容者，本公司依法保留追究权。
 * © 2018 Lynxi Technologies Co., Ltd. All rights reserved.
 * NOTICE: All information contained here is, and remains the property of Lynxi. This file can not
 * be copied or distributed without the permission of Lynxi Technologies Co., Ltd.
"""

import sys

sys.path.append("../../../")

from face_recognition import FaceRecognition
from common.python.callback_data_struct import *
from common.python.infer_process import *
from ctypes import *

import pylynchipsdk as sdk
import common.python.common as common
import argparse
import os
import signal
import multiprocessing
import signal


# Create a shared boolean value to stop running thread
cancel_flag = multiprocessing.Value("b", False)


def main(args, video_frame) -> None:
    worker = FaceRecognition()
    worker.print_stats = args.print_stats
    worker.input_file = args.input_video
    if args.show_type == 1:
        worker.output_path = common.append_text_to_filename(
            common.change_file_extension(args.input_video, ".264"),
            f"_device_{args.device_id}_channel_{args.channel_id}",
        )
    elif args.show_type == 2:
        worker.output_path = common.append_text_to_filename(
            common.change_file_extension(args.input_video, "_BoxInfo.json"),
            f"_device_{args.device_id}_channel_{args.channel_id}",
        )
    if args.show_type > 2 or args.show_type < 0:
        raise ("supported show type: 0 or 1 or 2, got args.show_type")
    if os.path.exists(worker.output_path):
        os.remove(worker.output_path)
    worker.device_id = args.device_id
    worker.channel_id = args.channel_id
    worker.post_plugin_path = args.face_detect_post_plugin
    worker.osd_plugin_path = args.osd_plugin
    worker.detect_model_path = args.face_detect_model
    worker.recog_model_path = args.face_feature_model
    worker.show_type = args.show_type
    worker.video_frame = video_frame
    with open(args.face_lib) as f:
        worker.faces_config = json.load(f)
        worker.face_lib_labels = worker.faces_config["names"]
        worker.features_path = worker.faces_config["features"]

    if not worker.input_file:
        raise ValueError("input file miss!!!")
    if worker.show_type == 1 and not worker.output_path:
        raise ValueError("unspecified output path!!!")
    worker.init()
    worker.run(cancel_flag)
    worker.close()


def cancel_process(signum, frame):
    global cancel_flag
    cancel_flag.value = True


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="参数帮助信息")
    parser.add_argument(
        "-i",
        "--input_video",
        default="../../../data/face_recognition_with_video_sample/humans_5x.mp4",
        help="input MP4 video file path",
    )
    parser.add_argument(
        "-l",
        "--face_lib",
        default="../../../data/face_recognition_with_video_sample/face_config_py.json",
        help="input face lib config file path",
    )
    parser.add_argument(
        "-d",
        "--device_id",
        default="0",
        help="test device number which can be 0~N-1 (N is device count). eg.:0,1,2",
    )
    parser.add_argument(
        "-c", "--channel_num", type=int, default=1, help="channel count"
    )
    parser.add_argument(
        "-m1",
        "--face_detect_model",
        default="../../../model/scrfd_500m_b1_h640_w640_c3_iuint8_ofloat16_0000/Net_0",
        help="face detect model path",
    )
    parser.add_argument(
        "--face_detect_post_plugin",
        default="../../../common/plugin/postprocess/cross_compiled_lib/libScrfdPostPlugin.so",
        help="face detect post process plugin path",
    )
    parser.add_argument(
        "-m2",
        "--face_feature_model",
        default="../../../model/w600k_mbf_b1_h112_w112_c3_iuint8_ofloat16_0000/Net_0",
        help="face feature model path",
    )
    parser.add_argument(
        "--osd_plugin",
        default="../../../common/plugin/osd/lib/libOsdPlugin.so",
        help="osd plugin path",
    )
    parser.add_argument(
        "-s",
        "--show_type",
        type=int,
        default=1,
        help="0: show test file directly, 1: save test result to be a file, 2: only save apu + postProcess",
    )
    parser.add_argument(
        "--print_stats",
        type=int,
        default=0,
        help="0: print frame rate only, 1: print more info",
    )

    args = parser.parse_args()
    args.config_file = None

    if args.config_file:
        argUsingJson = True

        if not os.path.exists(args.json_config):
            raise ("error: config file is not exist.")

    else:
        argUsingJson = False
        argInputVideo = args.input_video
        argFaceLibConfig = args.face_lib
        argChipsVec = [int(chip_id) for chip_id in args.device_id.split(",")]
        argChannel = args.channel_num
        argFaceDetectModelPath = args.face_detect_model
        argFaceDetectPostPluginPath = args.face_detect_post_plugin
        argFaceFeatureModelPath = args.face_feature_model
        argOsdPluginPath = args.osd_plugin
        argShowType = args.show_type
        argPrintStats = args.print_stats

        if not os.path.exists(argFaceLibConfig):
            raise ("error: face lib config file is not exist.")

        if not os.path.exists(argFaceDetectModelPath):
            raise ("error: face detect model is not exist.")

        if not os.path.exists(argFaceDetectPostPluginPath):
            raise ("error: face detect post plugin is not exist.")

        if not os.path.exists(argFaceFeatureModelPath):
            raise ("error: face feature model is not exist.")

        if not os.path.exists(argOsdPluginPath):
            raise ("error: osd plugin is not exist.")

        if argShowType < 0 or argShowType >= 3:
            raise ("error: show type is invalid.")

        if argChannel > 32:
            argChannel = 32
            raise (f"info: channel is not more than 32, it is set to 32")
        elif argChannel < 1:
            argChannel = 1
            raise ("info: channel is less than 1, it is set to 1")

    signal.signal(signal.SIGINT, cancel_process)

    channel_infos = get_channel_infos(args)
    start_process(main, channel_infos, cancel_flag)
